Introduction
This case study was undertaken in order to explore and shed light on the complex relationship between a person’s age and physical performance. Data used comes from the infamous Credit Union Cherry Blossom race. The Cherry Blossom Ten Mile Run is held every year during the month of April in Washington, D.C. when cherry blossom trees are said to bloom. Race results for the Cherry Blossom Ten Mile Run are available to the public online at http://www.cherryblossom.org/ and currently include annual results spanning from 1999 to 2012 (14 years in total). The race began in 1973 and has since grown by tens of thousands of runners to 17,000 entries in 2012 with ages ranging from 9 to 89. In fact, the race has been in such high demand that runners are chosen via a lottery system to enter the race. Because of the enormous amount of observations there is a clear abundance of information that can be used as a resource for investigating the performance-age relationship.
To that end, while this information is free and available to the public, what information is reported and how the data is formatted changes each year, presenting a challenge that must first be overcome before conducting further analysis. Therefore, after data clean up is performed and race results data tables are read into R, we then turn our focus to the age distribution of runners across all 14 years of the races, as we have seen that the 1999 runners were typically older than the 2012 runners [1]. This is achieved by creating visual representations of the data through QQ-plots, boxplots, and density curves. These visualizations are important for gaining deeper insights by seeing how fast or gradual changes are over time, as well as any outliers or subtle trends. For the purposes of this case study, only these three categories of plots are considered for only male runners and compared for a final analysis to ultimately determine how the distributions change over the years and if the changes was gradual.
Results
Data Acquisition
To begin, we utilized methods provided in the Data Science in R text to load male runners from 1999 to 2012. As the purpose of this analysis is to research this data post load, we have excluded the scraping process from this analysis and the data is loaded external to the notebook in the DataExtractAndClean.R file allowing us to focus on our analysis of age distributions.
Data Cleanup for Outlier Removal
Before beginning our analysis of age distributions, we have some preliminary data cleanup to perform on multiple scenarios, as this analysis is meant to represent the general population less outliers. First, there is 1 observation which appears to contain an outlier for its run-time; a 70 year old with a run-time of 1.5 which is likely either due to a non-starter or a data entry error.
Second, we identify 21 observations which have null values for age. These records are unable to be visualized for age distributions, and thus removed as well.
Lastly, we identify 10 observations with an age less than 10. Although there could be a young child in the run, there are several of these values with an age between 0 and 4, leaving us untrusting of the other three values remaining for 8 and 9 year olds. Due to this, we have decide to cut off the age lower limit at 10 years old to describe general population.
cbMenSub = cbMen[cbMen$runTime > 30 & !is.na(cbMen$age) & cbMen$age >= 10, ]
With these few outliers removed, we transform from 70070 to 70038 observations. We are now ready to move forward with our analysis of age distributions amongst each year.
Density Curve
To begin our density curve analysis, we first were interested in the overall distribution of age in the population across all years. Across all 14 years, the mean age is 38.611311, whereas the median age is 37. This suggests, since the mean value is larger than the median, that we have a slightly right-skewed distribution. Breaking age into bins of decade groups (10-20, 20-30,…,70,80, etc.), we are able to visualize the overall distribution of age. These bin counts help further these findings, with our most frequency bin including ages 30-40, the same identified for mean and median age. The distribution of bin counts also further supports the right-skew distribution as there is a slightly longer tail from 40-90 in comparison to that between 10-30.
ageCat = cut(cbMenSub$age, breaks = c(seq(10, 80, 10), 90))
bins=as.data.frame(table(ageCat))
bins.p <-ggplot(bins, aes(x=ageCat, y=Freq)) + geom_bar(stat="identity")
bins.p<-ggplotly(bins.p)
bins.p
To further this analysis, we are interested to see how age distribution has changed over the many years this race has been conducted. Below is a stacked density plot, providing a single curve for every year. Noteworthy to mention, the plot provided is rendered with plotly, allowing interactive hover values, zoom controls, and toggling of years to display by clicking on the legend. Before targetting specific years, there appears to be a notable decrease in mean age from 1999 to recent years. Additionally, earlier years appear to have a much more normal distribution in age than that of recent years.
By clicking on individual legend years {1999, 2004, 2008, 2012}, we may de-clutter the visual for further research into these findings on a wide spread of year runs. The mean age may be seen in the table below.
| 1999 |
40.3352148 |
| 2004 |
39.3128008 |
| 2008 |
37.7835732 |
| 2012 |
37.7528856 |
As was originally gleamed, ages steadily decrease from a mean of 40.3352148 to 37.7528856 years old. as the density curves also suggest, we observe the curves shift positions from right to left and density skewness elongate as we progress from early to recent years. These findings confirm our original observations, indicating that the core demographic for participating runners are decreasing year after year. We speculate this decrease will slow down moving forward, just as was seen from 2008 to 2012, with only a 0.0306877 difference in mean age in those years since participants under 20 have been insignificant across all years of the race. Although the mean distribution is shifting left, it is apparent that participation amongst the age groups above 40 have not significantly decreased. Because of this, we begin seeing the right-skew distribution increase in the most recent years of the race.
# Subset in order to color by year
cbMensPlot <- cbMenSub
cbMensPlot$year <- as.character(cbMensPlot$year)
age.d = ggplot(cbMensPlot, aes(age, color = year)) + geom_density() + scale_x_continuous(breaks = pretty(cbMensPlot$age, n = 10))
age.d = ggplotly(age.d) #Convert to plotly version
age.d
Quantile-Quantile Plots
Next in our analysis, we are interested to further build our case on normality of age distributions across the many years of the race. To do this, we decide to produce a Quantile-Quantile Plot (QQPlot) to assess our data’s quantiles against a theoretical normal distribution quantile. If our data poses as perfectly normal, we would see a straight line. The more our scatter varies from the ideal line, the further from normality is the distribution.
In efforts to create an interactive plotly visualization for these QQPlots as was done for density curves, the rendering was overbearing in terms of performance. Due to these issues, the stacked (static) ggplot visual is provided, however very difficult to gleam insights from. It is apparent that several of these years have normality problems, however very difficult to understand which years the plot references.
# calculate the normal theoretical quantiles per group
cbMensPlotQQ <- ddply(.data = cbMensPlot, .variables = .(year),
function(dsub){
q <- qqnorm(dsub$age, plot = FALSE)
dsub$xq <- q$x
dsub
})
age.qq = ggplot(data = cbMensPlotQQ, aes(x = xq, y = age, color = year)) +
geom_point() +
geom_smooth(method = "lm", se = FALSE) +
xlab("Normal Theoretical Quantiles") +
ylab("Normal Data Quantiles")
#age.qq = ggplotly(age.qq)
age.qq

To mitigate these issues, we build ggplot rendering of each year individually below in order to assess individually in comparison to the others. Although none of these plots provide us with a “perfect” line representing normality, we can assert that over time the distributions for age become less normal. Looking at the same years {1999,2004, 2008, 2012} as was done previously, we see very strong normality between ~30-60 years of age in the 1999 race. Moving towards 2004, we begin to see the scatter dip below the normality line, and a larger variation under 30 than was seen before. In 2008, we once again see the scatter dropping below the normality line, and increasing variance in both ages under 30 and those above 50 years old. Finally, in 2012, we see variation amongst the majority of the scatter and the normality line. These results help to further support those findings provided from density curves, in that normality in age distributions has began to shift. In recent years, we begin to have a skewed distribution, likely caused by the increased participation of the younger individuals.
plot.list <- list()
i = 1
#color.vect <- c('#D32F2F', '#C2185B', '#7B1FA2', '#512DA8', '#303F9F', '#1976D2', '#0288D1',
# '#0097A7', '#00796B', '#388E3C', '#689F38', '#AFB42B', '#FBC02D', '#FFA000')
for(yr in unique(cbMensPlot$year)){
cbMensPlotQQ <- ddply(.data = subset(cbMensPlot, cbMensPlot$year == yr), .variables = .(year),
function(dsub){
q <- qqnorm(dsub$age, plot = FALSE)
dsub$xq <- q$x
dsub
})
age.qq = ggplot(data = cbMensPlotQQ, aes(x = xq, y = age, color = year)) +
geom_point() +
geom_smooth(method = "lm", se = FALSE) +
xlab("Normal Theoretical Quantiles") +
ylab("Normal Data Quantiles")
#ggplot doesn't like to evaluate vector indexed contents so having to explicitly write color values line-by-line
if(i==1) plot.list[[i]] <- age.qq + scale_color_manual(values='#D32F2F')
if(i==2) plot.list[[i]] <- age.qq + scale_color_manual(values='#C2185B')
if(i==3) plot.list[[i]] <- age.qq + scale_color_manual(values='#7B1FA2')
if(i==4) plot.list[[i]] <- age.qq + scale_color_manual(values='#512DA8')
if(i==5) plot.list[[i]] <- age.qq + scale_color_manual(values='#303F9F')
if(i==6) plot.list[[i]] <- age.qq + scale_color_manual(values='#1976D2')
if(i==7) plot.list[[i]] <- age.qq + scale_color_manual(values='#0288D1')
if(i==8) plot.list[[i]] <- age.qq + scale_color_manual(values='#0097A7')
if(i==9) plot.list[[i]] <- age.qq + scale_color_manual(values='#00796B')
if(i==10) plot.list[[i]] <- age.qq + scale_color_manual(values='#388E3C')
if(i==11) plot.list[[i]] <- age.qq + scale_color_manual(values='#689F38')
if(i==12) plot.list[[i]] <- age.qq + scale_color_manual(values='#AFB42B')
if(i==13) plot.list[[i]] <- age.qq + scale_color_manual(values='#FBC02D')
if(i==14) plot.list[[i]] <- age.qq + scale_color_manual(values='#FFA000')
#plot.list[[i]] <- age.qq + scale_color_manual(values=eval(as.character(color.vect[i])))
i = i + 1
}
grid.arrange(plot.list[[1]],
plot.list[[2]],
plot.list[[3]],
plot.list[[4]],
plot.list[[5]],
plot.list[[6]],
plot.list[[7]],
plot.list[[8]],
plot.list[[9]],
plot.list[[10]],
plot.list[[11]],
plot.list[[12]],
plot.list[[13]],
plot.list[[14]], ncol=2)

Boxplots
After cleaning up the data and displaying it as a boxplot (below) we can better analyze the age and year variables. While there is not a significant difference between the second and third quartiles between 1999 and 2012, it is clear the median age for runners in 2012 is lower than 1999. Also, a quick look at the boxplots shows the median age value gradually decreasing over time, with 2011 as the only exception. A closer look at the boxplot statistics shows the median age of runners in 1999 was 40, while the median age of runner in 2012 was 36. Another interesting metric is the number of observations also increased each year from 3189 in 1999 to 7191 in 2012. The data, as shown in the boxplot, does not have any significant outliers which leads to the conclusion the data is reliable and shows a gradual decline in the age of runners over time.
# str(cbMenSub)
#
# bp <- boxplot(cbMenSub$age ~ cbMenSub$year, ylab = "Age", xlab = "Year", col = c
# ("red","sienna","palevioletred1","royalblue2","cadetblue","burlywood3","chartreuse",
# "cyan4","darkgoldenrod","darkorange1","firebrick","dodgerblue", "forestgreen"), las = 2)
# bp
# bp$stats[3,]
bp.p <- ggplot(cbMensPlot, aes(x=year, y=age, fill=year)) + geom_boxplot() + theme(axis.text.x = element_text(angle = 45, hjust = 1)) + scale_y_continuous(breaks = pretty(cbMensPlot$age, n = 10))+
stat_summary(fun.y=mean, geom="point", shape=5, size=4)
bp.p <- ggplotly(bp.p)
bp.p
LS0tDQp0aXRsZTogIk1vZGVsaW5nIFJ1bm5lcnMnIFRpbWVzIGluIHRoZSBDaGVycnkgQmxvc3NvbSBSYWNlIC0gQ2FzZSBTdHVkeSBVbml0IDgiDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQojIyMjQ29yeSBBZGFtcywgQ2hyaXMgQm9vbWhvd2VyLCBBbGV4YW5kcmEgRmlzaGVyLCBBbGV4IEZyeWUNCiMjIyNNU0RTIDczMzMsIE9jdG9iZXIgMjUsIDIwMTcNCg0KKioqTk9URTogQW5zd2VyaW5nIFEuMTA6IFdlIGhhdmUgc2VlbiB0aGF0IHRoZSAxOTk5IHJ1bm5lcnMgd2VyZSB0eXBpY2FsbHkgb2xkZXIgdGhhbiB0aGUgMjAxMiBydW5uZXJzLg0KQ29tcGFyZSB0aGUgYWdlIGRpc3RyaWJ1dGlvbiBvZiB0aGUgcnVubmVycyBhY3Jvc3MgYWxsIDE0IHllYXJzIG9mIHRoZSByYWNlcy4gVXNlIHF1YW50aWxlLQ0KcXVhbnRpbGUgcGxvdHMsIGJveHBsb3RzLCBhbmQgZGVuc2l0eSBjdXJ2ZXMgdG8gbWFrZSB5b3VyIGNvbXBhcmlzb25zLiBIb3cgZG8gdGhlDQpkaXN0cmlidXRpb25zIGNoYW5nZSBvdmVyIHRoZSB5ZWFycz8gV2FzIGl0IGEgZ3JhZHVhbCBjaGFuZ2U/KioqDQoNCiMjQWJzdHJhY3QNCkluIHRoaXMgY2FzZSBzdHVkeSwgcmFjZSByZXN1bHRzIGZvciB0aGUgQ2hlcnJ5IEJsb3Nzb20gVGVuIE1pbGUgUnVuIGZyb20gMTk5OSB0byAyMDEyIGFyZSB1c2VkIHRvIHN0dWR5IGhvdyBwZW9wbGXigJlzIHBoeXNpY2FsIHBlcmZvcm1hbmNlIGNoYW5nZXMgd2l0aCBhZ2UgWzFdLiBUaGUgZm9jdXMgb2YgdGhlIHN0dWR5IGludm9sdmVzIHNjcmFwaW5nIHRoZSBXZWIgZm9yIGZyZWUgYW5kIHB1YmxpY2x5IHB1Ymxpc2hlZCBkYXRhIGFuZCB0aGVuIGdldHRpbmcgdGhhdCBkYXRhIGludG8gdGhlIGNvcnJlY3QgZm9ybWF0LiBJbiBvcmRlciB0byBpbnZlc3RpZ2F0ZSBob3cgYWdlIGRpc3RyaWJ1dGlvbnMgY2hhbmdlIG92ZXIgdGhlIHllYXJzLCBhZ2UgZGlzdHJpYnV0aW9uIGZvciBhbGwgcnVubmVycyBhY3Jvc3MgMTQgeWVhcnMgaXMgY29tcGFyZWQ7IGhvd2V2ZXIsIHdoYXQgaW5mb3JtYXRpb24gaXMgcmVjb3JkZWQgYW5kIGhvdyB0aGUgZGF0YSBpcyBmb3JtYXR0ZWQgY2hhbmdlcyBlYWNoIHllYXIgc28gY2xvc2UgYXR0ZW50aW9uIGlzIHBhaWQgZmlyc3QgdG8gZm9ybWF0dGluZyB0aGUgZGF0YS4gVGhlIFIgbGFuZ3VhZ2UgaXMgbGV2ZXJhZ2VkIHRvIGFwcHJvcHJpYXRlbHkgZm9ybWF0IHRoZSBkYXRhIHZpYSBzdGF0aXN0aWNhbCBhbmFseXNpcyBhbmQgZXhhbWluaW5nIHN1bW1hcnkgc3RhdGlzdGljcyBhbmQgcGxvdHMuIEZvbGxvd2luZyBkYXRhIGFjcXVpc2l0aW9uIGFuZCBzdWNjZXNzZnVsbHkgcmVhZGluZyB0YWJsZXMgb2YgcmFjZSByZXN1bHRzIGludG8gUiwgcmVzdWx0cyBhcmUgYW5hbHl6ZWQgYW5kIGNvbXBhcmVkIHVzaW5nIHF1YW50aWxlLXF1YW50aWxlIHBsb3RzLCBib3hwbG90cywgYW5kIGRlbnNpdHkgY3VydmVzLiBJbiB0aGlzIHdheSwgd2UgYXJlIGFibGUgdG8gdmlzdWFsaXplIHRoZSBkYXRhIGZvciB0ZW5zIG9mIHRob3VzYW5kcyBvZiBvYnNlcnZhdGlvbnMgdG8gZXhwbG9yZSB0aGUgcGVyZm9ybWFuY2UtYWdlIHJlbGF0aW9uc2hpcC4gW2luc2VydCByZXN1bHRzIC8gZmluYWwgb3V0Y29tZV0NCg0KIyNJbnRyb2R1Y3Rpb24NClRoaXMgY2FzZSBzdHVkeSB3YXMgdW5kZXJ0YWtlbiBpbiBvcmRlciB0byBleHBsb3JlIGFuZCBzaGVkIGxpZ2h0IG9uIHRoZSBjb21wbGV4IHJlbGF0aW9uc2hpcCBiZXR3ZWVuIGEgcGVyc29uJ3MgYWdlIGFuZCBwaHlzaWNhbCBwZXJmb3JtYW5jZS4gRGF0YSB1c2VkIGNvbWVzIGZyb20gdGhlIGluZmFtb3VzIENyZWRpdCBVbmlvbiBDaGVycnkgQmxvc3NvbSByYWNlLiBUaGUgQ2hlcnJ5IEJsb3Nzb20gVGVuIE1pbGUgUnVuIGlzIGhlbGQgZXZlcnkgeWVhciBkdXJpbmcgdGhlIG1vbnRoIG9mIEFwcmlsIGluIFdhc2hpbmd0b24sIEQuQy4gd2hlbiBjaGVycnkgYmxvc3NvbSB0cmVlcyBhcmUgc2FpZCB0byBibG9vbS4gUmFjZSByZXN1bHRzIGZvciB0aGUgQ2hlcnJ5IEJsb3Nzb20gVGVuIE1pbGUgUnVuIGFyZSBhdmFpbGFibGUgdG8gdGhlIHB1YmxpYyBvbmxpbmUgYXQgaHR0cDovL3d3dy5jaGVycnlibG9zc29tLm9yZy8gYW5kIGN1cnJlbnRseSBpbmNsdWRlIGFubnVhbCByZXN1bHRzIHNwYW5uaW5nIGZyb20gMTk5OSB0byAyMDEyICgxNCB5ZWFycyBpbiB0b3RhbCkuIFRoZSByYWNlIGJlZ2FuIGluIDE5NzMgYW5kIGhhcyBzaW5jZSBncm93biBieSB0ZW5zIG9mIHRob3VzYW5kcyBvZiBydW5uZXJzIHRvIDE3LDAwMCBlbnRyaWVzIGluIDIwMTIgd2l0aCBhZ2VzIHJhbmdpbmcgZnJvbSA5IHRvIDg5LiBJbiBmYWN0LCB0aGUgcmFjZSBoYXMgYmVlbiBpbiBzdWNoIGhpZ2ggZGVtYW5kIHRoYXQgcnVubmVycyBhcmUgY2hvc2VuIHZpYSBhIGxvdHRlcnkgc3lzdGVtIHRvIGVudGVyIHRoZSByYWNlLiBCZWNhdXNlIG9mIHRoZSBlbm9ybW91cyBhbW91bnQgb2Ygb2JzZXJ2YXRpb25zIHRoZXJlIGlzIGEgY2xlYXIgYWJ1bmRhbmNlIG9mIGluZm9ybWF0aW9uIHRoYXQgY2FuIGJlIHVzZWQgYXMgYSByZXNvdXJjZSBmb3IgaW52ZXN0aWdhdGluZyB0aGUgcGVyZm9ybWFuY2UtYWdlIHJlbGF0aW9uc2hpcC4NCg0KVG8gdGhhdCBlbmQsIHdoaWxlIHRoaXMgaW5mb3JtYXRpb24gaXMgZnJlZSBhbmQgYXZhaWxhYmxlIHRvIHRoZSBwdWJsaWMsIHdoYXQgaW5mb3JtYXRpb24gaXMgcmVwb3J0ZWQgYW5kIGhvdyB0aGUgZGF0YSBpcyBmb3JtYXR0ZWQgY2hhbmdlcyBlYWNoIHllYXIsIHByZXNlbnRpbmcgYSBjaGFsbGVuZ2UgdGhhdCBtdXN0IGZpcnN0IGJlIG92ZXJjb21lIGJlZm9yZSBjb25kdWN0aW5nIGZ1cnRoZXIgYW5hbHlzaXMuIFRoZXJlZm9yZSwgYWZ0ZXIgZGF0YSBjbGVhbiB1cCBpcyBwZXJmb3JtZWQgYW5kIHJhY2UgcmVzdWx0cyBkYXRhIHRhYmxlcyBhcmUgcmVhZCBpbnRvIFIsIHdlIHRoZW4gdHVybiBvdXIgZm9jdXMgdG8gdGhlIGFnZSBkaXN0cmlidXRpb24gb2YgcnVubmVycyBhY3Jvc3MgYWxsIDE0IHllYXJzIG9mIHRoZSByYWNlcywgYXMgd2UgaGF2ZSBzZWVuIHRoYXQgdGhlIDE5OTkgcnVubmVycyB3ZXJlIHR5cGljYWxseSBvbGRlciB0aGFuIHRoZSAyMDEyIHJ1bm5lcnMgWzFdLiBUaGlzIGlzIGFjaGlldmVkIGJ5IGNyZWF0aW5nIHZpc3VhbCByZXByZXNlbnRhdGlvbnMgb2YgdGhlIGRhdGEgdGhyb3VnaCBRUS1wbG90cywgYm94cGxvdHMsIGFuZCBkZW5zaXR5IGN1cnZlcy4gVGhlc2UgdmlzdWFsaXphdGlvbnMgYXJlIGltcG9ydGFudCBmb3IgZ2FpbmluZyBkZWVwZXIgaW5zaWdodHMgYnkgc2VlaW5nIGhvdyBmYXN0IG9yIGdyYWR1YWwgY2hhbmdlcyBhcmUgb3ZlciB0aW1lLCBhcyB3ZWxsIGFzIGFueSBvdXRsaWVycyBvciBzdWJ0bGUgdHJlbmRzLiBGb3IgdGhlIHB1cnBvc2VzIG9mIHRoaXMgY2FzZSBzdHVkeSwgb25seSB0aGVzZSB0aHJlZSBjYXRlZ29yaWVzIG9mIHBsb3RzIGFyZSBjb25zaWRlcmVkIGZvciBvbmx5IG1hbGUgcnVubmVycyBhbmQgY29tcGFyZWQgZm9yIGEgZmluYWwgYW5hbHlzaXMgdG8gdWx0aW1hdGVseSBkZXRlcm1pbmUgaG93IHRoZSBkaXN0cmlidXRpb25zIGNoYW5nZSBvdmVyIHRoZSB5ZWFycyBhbmQgaWYgdGhlIGNoYW5nZXMgd2FzIGdyYWR1YWwuDQoNCiMjTWV0aG9kcw0KVGhlIHN0ZXBzIHVzZWQgZm9yIHRoaXMgYW5hbHlzaXMgd2VyZTogMSkgZGF0YSBhY3F1aXN0aW9uOyAyKSBBZGRpdGlvbmFsIERhdGEgY2xlYW51cCBmb3Igb3V0bGllciByZW1vdmFsOyAzKSBkZW5zaXR5IGN1cnZlcyBhbmFseXNpczsgNCkgcXVhbnRpbGUtcXVhbnRpbGUgcGxvdHMgYW5hbHlzaXM7IGFuZCA1KSBib3hwbG90cyBhbmFseXNpcy4NCg0KKk5vdGUgdGhhdCBjb2RlIHVzZWQgaW5jbHVkZXMgbW9kaWZpZWQgdmVyc2lvbnMgb2YgUiBjb2RlIGZ1bmN0aW9uIGV4YW1wbGVzIGZvdW5kIGluIERhdGEgU2NpZW5jZSBpbiBSOiBBIENhc2UgU3R1ZGllcyBBcHByb2FjaCB0byBDb21wdXRhdGlvbmFsIFJlYXNvbmluZyBhbmQgUHJvYmxlbSBTb2x2aW5nLCBDaGFwdGVyIDIsIHBhZ2VzIDQ3LTEwMCBbMV0uKg0KDQojI1Jlc3VsdHMNCg0KIyMjI0RhdGEgQWNxdWlzaXRpb24NClRvIGJlZ2luLCB3ZSB1dGlsaXplZCBtZXRob2RzIHByb3ZpZGVkIGluIHRoZSBEYXRhIFNjaWVuY2UgaW4gUiB0ZXh0IHRvIGxvYWQgbWFsZSBydW5uZXJzIGZyb20gMTk5OSB0byAyMDEyLiBBcyB0aGUgcHVycG9zZSBvZiB0aGlzIGFuYWx5c2lzIGlzIHRvIHJlc2VhcmNoIHRoaXMgZGF0YSBwb3N0IGxvYWQsIHdlIGhhdmUgZXhjbHVkZWQgdGhlIHNjcmFwaW5nIHByb2Nlc3MgZnJvbSB0aGlzIGFuYWx5c2lzIGFuZCB0aGUgZGF0YSBpcyBsb2FkZWQgZXh0ZXJuYWwgdG8gdGhlIG5vdGVib29rIGluIHRoZSBgYGBEYXRhRXh0cmFjdEFuZENsZWFuLlJgYGAgZmlsZSBhbGxvd2luZyB1cyB0byBmb2N1cyBvbiBvdXIgYW5hbHlzaXMgb2YgYWdlIGRpc3RyaWJ1dGlvbnMuDQpgYGB7ciBpbmNsdWRlPUZBTFNFLCBjYWNoZT1UUlVFfQ0Kc291cmNlKCdEYXRhRXh0cmFjdEFuZENsZWFuLlInLCBlY2hvID0gRkFMU0UpDQpgYGANCg0KDQpgYGB7ciBlY2hvPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nID0gRkFMU0V9DQojIyMjTG9hZCBMaWJyYXJpZXMNCmxpYnJhcnkoZ2dwbG90MikNCmxpYnJhcnkocGxvdGx5KQ0KbGlicmFyeShwbHlyKQ0KbGlicmFyeShncmlkKQ0KbGlicmFyeShncmlkRXh0cmEpDQpsaWJyYXJ5KGZvcm1hdHRhYmxlKQ0KYGBgDQoNCiMjIyNEYXRhIENsZWFudXAgZm9yIE91dGxpZXIgUmVtb3ZhbA0KYGBge3IgZWNobyA9ICJmYWxzZSJ9DQpsZW5MUlQ8LW5yb3coY2JNZW5bY2JNZW4kcnVuVGltZSA8IDMwLCBdKQ0KbGVuTkFBRzwtbnJvdyhjYk1lbltpcy5uYShjYk1lbiRhZ2UpLCBdKQ0KbGVuTEFHPC1ucm93KGNiTWVuW2NiTWVuJGFnZSA8IDEwICYgIWlzLm5hKGNiTWVuJGFnZSksIF0pDQpsZW5Ub3REaXJ0eTwtbnJvdyhjYk1lbikNCmxlblRvdENsZWFuPC1ucm93KGNiTWVuW2NiTWVuJHJ1blRpbWUgPiAzMCAmICFpcy5uYShjYk1lbiRhZ2UpICYgY2JNZW4kYWdlID49IDEwLCBdKQ0KYGBgDQoNCkJlZm9yZSBiZWdpbm5pbmcgb3VyIGFuYWx5c2lzIG9mIGFnZSBkaXN0cmlidXRpb25zLCB3ZSBoYXZlIHNvbWUgcHJlbGltaW5hcnkgZGF0YSBjbGVhbnVwIHRvIHBlcmZvcm0gb24gbXVsdGlwbGUgc2NlbmFyaW9zLCBhcyB0aGlzIGFuYWx5c2lzIGlzIG1lYW50IHRvIHJlcHJlc2VudCB0aGUgZ2VuZXJhbCBwb3B1bGF0aW9uIGxlc3Mgb3V0bGllcnMuIEZpcnN0LCB0aGVyZSBpcyBgYGBgciBsZW5MUlRgYGBgIG9ic2VydmF0aW9uIHdoaWNoIGFwcGVhcnMgdG8gY29udGFpbiBhbiBvdXRsaWVyIGZvciBpdHMgcnVuLXRpbWU7IGEgNzAgeWVhciBvbGQgd2l0aCBhIHJ1bi10aW1lIG9mIDEuNSB3aGljaCBpcyBsaWtlbHkgZWl0aGVyIGR1ZSB0byBhIG5vbi1zdGFydGVyIG9yIGEgZGF0YSBlbnRyeSBlcnJvci4gDQoNCmBgYHtyIGVjaG8gPSAiZmFsc2UifQ0KZm9ybWF0dGFibGUoY2JNZW5bY2JNZW4kcnVuVGltZSA8IDMwLCBdKQ0KYGBgDQoNClNlY29uZCwgd2UgaWRlbnRpZnkgYGBgYHIgbGVuTkFBR2BgYGAgb2JzZXJ2YXRpb25zIHdoaWNoIGhhdmUgbnVsbCB2YWx1ZXMgZm9yIGFnZS4gVGhlc2UgcmVjb3JkcyBhcmUgdW5hYmxlIHRvIGJlIHZpc3VhbGl6ZWQgZm9yIGFnZSBkaXN0cmlidXRpb25zLCBhbmQgdGh1cyByZW1vdmVkIGFzIHdlbGwuIA0KDQpgYGB7ciBlY2hvID0gImZhbHNlIn0NCmZvcm1hdHRhYmxlKGNiTWVuW2lzLm5hKGNiTWVuJGFnZSksIF0pDQpgYGANCg0KTGFzdGx5LCB3ZSBpZGVudGlmeSBgYGBgciBsZW5MQUdgYGBgIG9ic2VydmF0aW9ucyB3aXRoIGFuIGFnZSBsZXNzIHRoYW4gMTAuIEFsdGhvdWdoIHRoZXJlIGNvdWxkIGJlIGEgeW91bmcgY2hpbGQgaW4gdGhlIHJ1biwgIHRoZXJlIGFyZSBzZXZlcmFsIG9mIHRoZXNlIHZhbHVlcyB3aXRoIGFuIGFnZSBiZXR3ZWVuIDAgYW5kIDQsIGxlYXZpbmcgdXMgdW50cnVzdGluZyBvZiB0aGUgb3RoZXIgdGhyZWUgdmFsdWVzIHJlbWFpbmluZyBmb3IgOCBhbmQgOSB5ZWFyIG9sZHMuIER1ZSB0byB0aGlzLCB3ZSBoYXZlIGRlY2lkZSB0byBjdXQgb2ZmIHRoZSBhZ2UgbG93ZXIgbGltaXQgYXQgMTAgeWVhcnMgb2xkIHRvIGRlc2NyaWJlIGdlbmVyYWwgcG9wdWxhdGlvbi4gDQoNCmBgYHtyIGVjaG8gPSAiZmFsc2UifQ0KZm9ybWF0dGFibGUoY2JNZW5bY2JNZW4kYWdlIDwgMTAgJiAhaXMubmEoY2JNZW4kYWdlKSwgXSkNCmBgYA0KDQpgYGB7cn0NCmNiTWVuU3ViID0gY2JNZW5bY2JNZW4kcnVuVGltZSA+IDMwICYgIWlzLm5hKGNiTWVuJGFnZSkgJiBjYk1lbiRhZ2UgPj0gMTAsIF0NCmBgYA0KDQpXaXRoIHRoZXNlIGZldyBvdXRsaWVycyByZW1vdmVkLCB3ZSB0cmFuc2Zvcm0gZnJvbSBgYGBgciBsZW5Ub3REaXJ0eWBgYGAgdG8gYGBgYHIgbGVuVG90Q2xlYW5gYGBgIG9ic2VydmF0aW9ucy4gV2UgYXJlIG5vdyByZWFkeSB0byBtb3ZlIGZvcndhcmQgd2l0aCBvdXIgYW5hbHlzaXMgb2YgYWdlIGRpc3RyaWJ1dGlvbnMgYW1vbmdzdCBlYWNoIHllYXIuDQoNCiMjIyNEZW5zaXR5IEN1cnZlDQpgYGB7ciBlY2hvID0gImZhbHNlIn0NCm1lYW5BZ2VBbGxZcnMgPC0gbWVhbihjYk1lblN1YiRhZ2UpDQpNZWRpYW5BZ2VBbGxZcnMgPC0gbWVkaWFuKGNiTWVuU3ViJGFnZSkNCk1lYW4xOTk5QWdlIDwtbWVhbihjYk1lblN1YltjYk1lblN1YiR5ZWFyPT0xOTk5LCJhZ2UiXSkNCk1lYW4yMDA0QWdlIDwtbWVhbihjYk1lblN1YltjYk1lblN1YiR5ZWFyPT0yMDA0LCJhZ2UiXSkNCk1lYW4yMDA4QWdlIDwtbWVhbihjYk1lblN1YltjYk1lblN1YiR5ZWFyPT0yMDA4LCJhZ2UiXSkNCk1lYW4yMDEyQWdlIDwtbWVhbihjYk1lblN1YltjYk1lblN1YiR5ZWFyPT0yMDEyLCJhZ2UiXSkNCmBgYA0KVG8gYmVnaW4gb3VyIGRlbnNpdHkgY3VydmUgYW5hbHlzaXMsIHdlIGZpcnN0IHdlcmUgaW50ZXJlc3RlZCBpbiB0aGUgb3ZlcmFsbCBkaXN0cmlidXRpb24gb2YgYWdlIGluIHRoZSBwb3B1bGF0aW9uIGFjcm9zcyBhbGwgeWVhcnMuIEFjcm9zcyBhbGwgMTQgeWVhcnMsIHRoZSBtZWFuIGFnZSBpcyBgYGBgciBtZWFuQWdlQWxsWXJzYGBgYCwgd2hlcmVhcyB0aGUgbWVkaWFuIGFnZSBpcyBgYGBgciBNZWRpYW5BZ2VBbGxZcnNgYGBgLiBUaGlzIHN1Z2dlc3RzLCBzaW5jZSB0aGUgbWVhbiB2YWx1ZSBpcyBsYXJnZXIgdGhhbiB0aGUgbWVkaWFuLCB0aGF0IHdlIGhhdmUgYSBzbGlnaHRseSByaWdodC1za2V3ZWQgZGlzdHJpYnV0aW9uLiBCcmVha2luZyBhZ2UgaW50byBiaW5zIG9mIGRlY2FkZSBncm91cHMgKDEwLTIwLCAyMC0zMCwuLi4sNzAsODAsIGV0Yy4pLCB3ZSBhcmUgYWJsZSB0byB2aXN1YWxpemUgdGhlIG92ZXJhbGwgZGlzdHJpYnV0aW9uIG9mIGFnZS4gVGhlc2UgYmluIGNvdW50cyBoZWxwIGZ1cnRoZXIgdGhlc2UgZmluZGluZ3MsIHdpdGggb3VyIG1vc3QgZnJlcXVlbmN5IGJpbiBpbmNsdWRpbmcgYWdlcyAzMC00MCwgdGhlIHNhbWUgaWRlbnRpZmllZCBmb3IgbWVhbiBhbmQgbWVkaWFuIGFnZS4gVGhlIGRpc3RyaWJ1dGlvbiBvZiBiaW4gY291bnRzIGFsc28gZnVydGhlciBzdXBwb3J0cyB0aGUgcmlnaHQtc2tldyBkaXN0cmlidXRpb24gYXMgdGhlcmUgaXMgYSBzbGlnaHRseSBsb25nZXIgdGFpbCBmcm9tIDQwLTkwIGluIGNvbXBhcmlzb24gdG8gdGhhdCBiZXR3ZWVuIDEwLTMwLg0KDQpgYGB7cn0NCmFnZUNhdCA9IGN1dChjYk1lblN1YiRhZ2UsIGJyZWFrcyA9IGMoc2VxKDEwLCA4MCwgMTApLCA5MCkpDQpiaW5zPWFzLmRhdGEuZnJhbWUodGFibGUoYWdlQ2F0KSkNCg0KYmlucy5wIDwtZ2dwbG90KGJpbnMsIGFlcyh4PWFnZUNhdCwgeT1GcmVxKSkgKyBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIpDQpiaW5zLnA8LWdncGxvdGx5KGJpbnMucCkNCmJpbnMucA0KYGBgDQoNClRvIGZ1cnRoZXIgdGhpcyBhbmFseXNpcywgd2UgYXJlIGludGVyZXN0ZWQgdG8gc2VlIGhvdyBhZ2UgZGlzdHJpYnV0aW9uIGhhcyBjaGFuZ2VkIG92ZXIgdGhlIG1hbnkgeWVhcnMgdGhpcyByYWNlIGhhcyBiZWVuIGNvbmR1Y3RlZC4gQmVsb3cgaXMgYSBzdGFja2VkIGRlbnNpdHkgcGxvdCwgcHJvdmlkaW5nIGEgc2luZ2xlIGN1cnZlIGZvciBldmVyeSB5ZWFyLiBOb3Rld29ydGh5IHRvIG1lbnRpb24sIHRoZSBwbG90IHByb3ZpZGVkIGlzIHJlbmRlcmVkIHdpdGggcGxvdGx5LCBhbGxvd2luZyBpbnRlcmFjdGl2ZSBob3ZlciB2YWx1ZXMsIHpvb20gY29udHJvbHMsIGFuZCB0b2dnbGluZyBvZiB5ZWFycyB0byBkaXNwbGF5IGJ5IGNsaWNraW5nIG9uIHRoZSBsZWdlbmQuIEJlZm9yZSB0YXJnZXR0aW5nIHNwZWNpZmljIHllYXJzLCB0aGVyZSBhcHBlYXJzIHRvIGJlIGEgbm90YWJsZSBkZWNyZWFzZSBpbiBtZWFuIGFnZSBmcm9tIDE5OTkgdG8gcmVjZW50IHllYXJzLiBBZGRpdGlvbmFsbHksIGVhcmxpZXIgeWVhcnMgYXBwZWFyIHRvIGhhdmUgYSBtdWNoIG1vcmUgbm9ybWFsIGRpc3RyaWJ1dGlvbiBpbiBhZ2UgdGhhbiB0aGF0IG9mIHJlY2VudCB5ZWFycy4NCg0KQnkgY2xpY2tpbmcgb24gaW5kaXZpZHVhbCBsZWdlbmQgeWVhcnMgezE5OTksIDIwMDQsIDIwMDgsIDIwMTJ9LCB3ZSBtYXkgZGUtY2x1dHRlciB0aGUgdmlzdWFsIGZvciBmdXJ0aGVyIHJlc2VhcmNoIGludG8gdGhlc2UgZmluZGluZ3Mgb24gYSB3aWRlIHNwcmVhZCBvZiB5ZWFyIHJ1bnMuIFRoZSBtZWFuIGFnZSBtYXkgYmUgc2VlbiBpbiB0aGUgdGFibGUgYmVsb3cuIA0KDQp8ICBZZWFyICB8ICAgICBNZWFuIEFnZSAgICAgICAgICB8DQp8Oi0tLS0tLTp8Oi0tLS0tLS0tLS0tLS0tLS0tLS0tLTp8DQp8KioxOTk5Kip8IGBgYGByIE1lYW4xOTk5QWdlYGBgYCB8DQp8KioyMDA0Kip8IGBgYGByIE1lYW4yMDA0QWdlYGBgYCB8DQp8KioyMDA4Kip8IGBgYGByIE1lYW4yMDA4QWdlYGBgYCB8DQp8KioyMDEyKip8IGBgYGByIE1lYW4yMDEyQWdlYGBgYCB8DQoNCkFzIHdhcyBvcmlnaW5hbGx5IGdsZWFtZWQsIGFnZXMgc3RlYWRpbHkgZGVjcmVhc2UgZnJvbSBhIG1lYW4gb2YgYGBgciBNZWFuMTk5OUFnZWBgYCB0byBgYGByIE1lYW4yMDEyQWdlYGBgIHllYXJzIG9sZC4gYXMgdGhlIGRlbnNpdHkgY3VydmVzIGFsc28gc3VnZ2VzdCwgd2Ugb2JzZXJ2ZSB0aGUgY3VydmVzIHNoaWZ0IHBvc2l0aW9ucyBmcm9tIHJpZ2h0IHRvIGxlZnQgYW5kIGRlbnNpdHkgc2tld25lc3MgZWxvbmdhdGUgYXMgd2UgcHJvZ3Jlc3MgZnJvbSBlYXJseSB0byByZWNlbnQgeWVhcnMuIFRoZXNlIGZpbmRpbmdzIGNvbmZpcm0gb3VyIG9yaWdpbmFsIG9ic2VydmF0aW9ucywgaW5kaWNhdGluZyB0aGF0IHRoZSBjb3JlIGRlbW9ncmFwaGljIGZvciBwYXJ0aWNpcGF0aW5nIHJ1bm5lcnMgYXJlIGRlY3JlYXNpbmcgeWVhciBhZnRlciB5ZWFyLiBXZSBzcGVjdWxhdGUgdGhpcyBkZWNyZWFzZSB3aWxsIHNsb3cgZG93biBtb3ZpbmcgZm9yd2FyZCwganVzdCBhcyB3YXMgc2VlbiBmcm9tIDIwMDggdG8gMjAxMiwgd2l0aCBvbmx5IGEgYGBgciBNZWFuMjAwOEFnZS1NZWFuMjAxMkFnZWBgYCBkaWZmZXJlbmNlIGluIG1lYW4gYWdlIGluIHRob3NlIHllYXJzIHNpbmNlIHBhcnRpY2lwYW50cyB1bmRlciAyMCBoYXZlIGJlZW4gaW5zaWduaWZpY2FudCBhY3Jvc3MgYWxsIHllYXJzIG9mIHRoZSByYWNlLiBBbHRob3VnaCB0aGUgbWVhbiBkaXN0cmlidXRpb24gaXMgc2hpZnRpbmcgbGVmdCwgaXQgaXMgYXBwYXJlbnQgdGhhdCBwYXJ0aWNpcGF0aW9uIGFtb25nc3QgdGhlIGFnZSBncm91cHMgYWJvdmUgNDAgaGF2ZSBub3Qgc2lnbmlmaWNhbnRseSBkZWNyZWFzZWQuIEJlY2F1c2Ugb2YgdGhpcywgd2UgYmVnaW4gc2VlaW5nIHRoZSByaWdodC1za2V3IGRpc3RyaWJ1dGlvbiBpbmNyZWFzZSBpbiB0aGUgbW9zdCByZWNlbnQgeWVhcnMgb2YgdGhlIHJhY2UuDQoNCmBgYHtyfQ0KIyBTdWJzZXQgaW4gb3JkZXIgdG8gY29sb3IgYnkgeWVhcg0KY2JNZW5zUGxvdCA8LSBjYk1lblN1Yg0KY2JNZW5zUGxvdCR5ZWFyIDwtIGFzLmNoYXJhY3RlcihjYk1lbnNQbG90JHllYXIpDQoNCg0KYWdlLmQgPSBnZ3Bsb3QoY2JNZW5zUGxvdCwgYWVzKGFnZSwgY29sb3IgPSB5ZWFyKSkgKyBnZW9tX2RlbnNpdHkoKSArIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBwcmV0dHkoY2JNZW5zUGxvdCRhZ2UsIG4gPSAxMCkpDQphZ2UuZCA9IGdncGxvdGx5KGFnZS5kKSAjQ29udmVydCB0byBwbG90bHkgdmVyc2lvbg0KYWdlLmQNCmBgYA0KDQojIyMjUXVhbnRpbGUtUXVhbnRpbGUgUGxvdHMNCk5leHQgaW4gb3VyIGFuYWx5c2lzLCB3ZSBhcmUgaW50ZXJlc3RlZCB0byBmdXJ0aGVyIGJ1aWxkIG91ciBjYXNlIG9uIG5vcm1hbGl0eSBvZiBhZ2UgZGlzdHJpYnV0aW9ucyBhY3Jvc3MgdGhlIG1hbnkgeWVhcnMgb2YgdGhlIHJhY2UuIFRvIGRvIHRoaXMsIHdlIGRlY2lkZSB0byBwcm9kdWNlIGEgUXVhbnRpbGUtUXVhbnRpbGUgUGxvdCAoUVFQbG90KSB0byBhc3Nlc3Mgb3VyIGRhdGEncyBxdWFudGlsZXMgYWdhaW5zdCBhIHRoZW9yZXRpY2FsIG5vcm1hbCBkaXN0cmlidXRpb24gcXVhbnRpbGUuIElmIG91ciBkYXRhIHBvc2VzIGFzIHBlcmZlY3RseSBub3JtYWwsIHdlIHdvdWxkIHNlZSBhIHN0cmFpZ2h0IGxpbmUuIFRoZSBtb3JlIG91ciBzY2F0dGVyIHZhcmllcyBmcm9tIHRoZSBpZGVhbCBsaW5lLCB0aGUgZnVydGhlciBmcm9tIG5vcm1hbGl0eSBpcyB0aGUgZGlzdHJpYnV0aW9uLg0KDQpJbiBlZmZvcnRzIHRvIGNyZWF0ZSBhbiBpbnRlcmFjdGl2ZSBwbG90bHkgdmlzdWFsaXphdGlvbiBmb3IgdGhlc2UgUVFQbG90cyBhcyB3YXMgZG9uZSBmb3IgZGVuc2l0eSBjdXJ2ZXMsIHRoZSByZW5kZXJpbmcgd2FzIG92ZXJiZWFyaW5nIGluIHRlcm1zIG9mIHBlcmZvcm1hbmNlLiBEdWUgdG8gdGhlc2UgaXNzdWVzLCB0aGUgc3RhY2tlZCAoc3RhdGljKSBnZ3Bsb3QgdmlzdWFsIGlzIHByb3ZpZGVkLCBob3dldmVyIHZlcnkgZGlmZmljdWx0IHRvIGdsZWFtIGluc2lnaHRzIGZyb20uIEl0IGlzIGFwcGFyZW50IHRoYXQgc2V2ZXJhbCBvZiB0aGVzZSB5ZWFycyBoYXZlIG5vcm1hbGl0eSBwcm9ibGVtcywgaG93ZXZlciB2ZXJ5IGRpZmZpY3VsdCB0byB1bmRlcnN0YW5kIHdoaWNoIHllYXJzIHRoZSBwbG90IHJlZmVyZW5jZXMuIA0KYGBge3J9DQojIGNhbGN1bGF0ZSB0aGUgbm9ybWFsIHRoZW9yZXRpY2FsIHF1YW50aWxlcyBwZXIgZ3JvdXANCmNiTWVuc1Bsb3RRUSA8LSBkZHBseSguZGF0YSA9IGNiTWVuc1Bsb3QsIC52YXJpYWJsZXMgPSAuKHllYXIpLA0KICAgICAgICAgICAgICAgICAgICAgIGZ1bmN0aW9uKGRzdWIpew0KICAgICAgICAgICAgICAgICAgICAgICAgICBxIDwtIHFxbm9ybShkc3ViJGFnZSwgcGxvdCA9IEZBTFNFKQ0KICAgICAgICAgICAgICAgICAgICAgICAgICBkc3ViJHhxIDwtIHEkeA0KICAgICAgICAgICAgICAgICAgICAgICAgICBkc3ViDQogICAgICAgICAgICAgICAgICAgICAgfSkNCg0KYWdlLnFxID0gZ2dwbG90KGRhdGEgPSBjYk1lbnNQbG90UVEsIGFlcyh4ID0geHEsIHkgPSBhZ2UsIGNvbG9yID0geWVhcikpICsNCiAgICAgICAgICAgICAgICBnZW9tX3BvaW50KCkgKw0KICAgICAgICAgICAgICAgIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIHNlID0gRkFMU0UpICsNCiAgICAgICAgICAgICAgICB4bGFiKCJOb3JtYWwgVGhlb3JldGljYWwgUXVhbnRpbGVzIikgKw0KICAgICAgICAgICAgICAgIHlsYWIoIk5vcm1hbCBEYXRhIFF1YW50aWxlcyIpDQojYWdlLnFxID0gZ2dwbG90bHkoYWdlLnFxKQ0KYWdlLnFxDQpgYGANCg0KVG8gbWl0aWdhdGUgdGhlc2UgaXNzdWVzLCB3ZSBidWlsZCBnZ3Bsb3QgcmVuZGVyaW5nIG9mIGVhY2ggeWVhciBpbmRpdmlkdWFsbHkgYmVsb3cgaW4gb3JkZXIgdG8gYXNzZXNzIGluZGl2aWR1YWxseSBpbiBjb21wYXJpc29uIHRvIHRoZSBvdGhlcnMuIEFsdGhvdWdoIG5vbmUgb2YgdGhlc2UgcGxvdHMgcHJvdmlkZSB1cyB3aXRoIGEgInBlcmZlY3QiIGxpbmUgcmVwcmVzZW50aW5nIG5vcm1hbGl0eSwgd2UgY2FuIGFzc2VydCB0aGF0IG92ZXIgdGltZSB0aGUgZGlzdHJpYnV0aW9ucyBmb3IgYWdlIGJlY29tZSBsZXNzIG5vcm1hbC4gTG9va2luZyBhdCB0aGUgc2FtZSB5ZWFycyB7MTk5OSwyMDA0LCAyMDA4LCAyMDEyfSBhcyB3YXMgZG9uZSBwcmV2aW91c2x5LCB3ZSBzZWUgdmVyeSBzdHJvbmcgbm9ybWFsaXR5IGJldHdlZW4gfjMwLTYwIHllYXJzIG9mIGFnZSBpbiB0aGUgMTk5OSByYWNlLiBNb3ZpbmcgdG93YXJkcyAyMDA0LCB3ZSBiZWdpbiB0byBzZWUgdGhlIHNjYXR0ZXIgZGlwIGJlbG93IHRoZSBub3JtYWxpdHkgbGluZSwgYW5kIGEgbGFyZ2VyIHZhcmlhdGlvbiB1bmRlciAzMCB0aGFuIHdhcyBzZWVuIGJlZm9yZS4gSW4gMjAwOCwgd2Ugb25jZSBhZ2FpbiBzZWUgdGhlIHNjYXR0ZXIgZHJvcHBpbmcgYmVsb3cgdGhlIG5vcm1hbGl0eSBsaW5lLCBhbmQgaW5jcmVhc2luZyB2YXJpYW5jZSBpbiBib3RoIGFnZXMgdW5kZXIgMzAgYW5kIHRob3NlIGFib3ZlIDUwIHllYXJzIG9sZC4gRmluYWxseSwgaW4gMjAxMiwgd2Ugc2VlIHZhcmlhdGlvbiBhbW9uZ3N0IHRoZSBtYWpvcml0eSBvZiB0aGUgc2NhdHRlciBhbmQgdGhlIG5vcm1hbGl0eSBsaW5lLiBUaGVzZSByZXN1bHRzIGhlbHAgdG8gZnVydGhlciBzdXBwb3J0IHRob3NlIGZpbmRpbmdzIHByb3ZpZGVkIGZyb20gZGVuc2l0eSBjdXJ2ZXMsIGluIHRoYXQgbm9ybWFsaXR5IGluIGFnZSBkaXN0cmlidXRpb25zIGhhcyBiZWdhbiB0byBzaGlmdC4gSW4gcmVjZW50IHllYXJzLCB3ZSBiZWdpbiB0byBoYXZlIGEgc2tld2VkIGRpc3RyaWJ1dGlvbiwgbGlrZWx5IGNhdXNlZCBieSB0aGUgaW5jcmVhc2VkIHBhcnRpY2lwYXRpb24gb2YgdGhlIHlvdW5nZXIgaW5kaXZpZHVhbHMuIA0KYGBge3IgZmlnLndpZHRoPTEyLCBmaWcuYXNwPTEuNX0NCg0KcGxvdC5saXN0IDwtIGxpc3QoKQ0KaSA9IDENCiNjb2xvci52ZWN0IDwtIGMoJyNEMzJGMkYnLCAnI0MyMTg1QicsICcjN0IxRkEyJywgJyM1MTJEQTgnLCAnIzMwM0Y5RicsICcjMTk3NkQyJywgJyMwMjg4RDEnLA0KIyAgICAgICAgICAgICAgICAnIzAwOTdBNycsICcjMDA3OTZCJywgJyMzODhFM0MnLCAnIzY4OUYzOCcsICcjQUZCNDJCJywgJyNGQkMwMkQnLCAnI0ZGQTAwMCcpDQoNCmZvcih5ciBpbiB1bmlxdWUoY2JNZW5zUGxvdCR5ZWFyKSl7DQogICAgY2JNZW5zUGxvdFFRIDwtIGRkcGx5KC5kYXRhID0gc3Vic2V0KGNiTWVuc1Bsb3QsIGNiTWVuc1Bsb3QkeWVhciA9PSB5ciksIC52YXJpYWJsZXMgPSAuKHllYXIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBmdW5jdGlvbihkc3ViKXsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHEgPC0gcXFub3JtKGRzdWIkYWdlLCBwbG90ID0gRkFMU0UpDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkc3ViJHhxIDwtIHEkeA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZHN1Yg0KICAgICAgICAgICAgICAgICAgICAgICAgICB9KQ0KICAgIA0KICAgIGFnZS5xcSA9IGdncGxvdChkYXRhID0gY2JNZW5zUGxvdFFRLCBhZXMoeCA9IHhxLCB5ID0gYWdlLCBjb2xvciA9IHllYXIpKSArDQogICAgICAgICAgICAgICAgICAgIGdlb21fcG9pbnQoKSArDQogICAgICAgICAgICAgICAgICAgIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIHNlID0gRkFMU0UpICsNCiAgICAgICAgICAgICAgICAgICAgeGxhYigiTm9ybWFsIFRoZW9yZXRpY2FsIFF1YW50aWxlcyIpICsNCiAgICAgICAgICAgICAgICAgICAgeWxhYigiTm9ybWFsIERhdGEgUXVhbnRpbGVzIikNCiAgICANCiAgICAjZ2dwbG90IGRvZXNuJ3QgbGlrZSB0byBldmFsdWF0ZSB2ZWN0b3IgaW5kZXhlZCBjb250ZW50cyBzbyBoYXZpbmcgdG8gZXhwbGljaXRseSB3cml0ZSBjb2xvciB2YWx1ZXMgbGluZS1ieS1saW5lDQogICAgaWYoaT09MSkgcGxvdC5saXN0W1tpXV0gPC0gYWdlLnFxICsgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz0nI0QzMkYyRicpDQogICAgaWYoaT09MikgcGxvdC5saXN0W1tpXV0gPC0gYWdlLnFxICsgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz0nI0MyMTg1QicpDQogICAgaWYoaT09MykgcGxvdC5saXN0W1tpXV0gPC0gYWdlLnFxICsgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz0nIzdCMUZBMicpDQogICAgaWYoaT09NCkgcGxvdC5saXN0W1tpXV0gPC0gYWdlLnFxICsgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz0nIzUxMkRBOCcpDQogICAgaWYoaT09NSkgcGxvdC5saXN0W1tpXV0gPC0gYWdlLnFxICsgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz0nIzMwM0Y5RicpDQogICAgaWYoaT09NikgcGxvdC5saXN0W1tpXV0gPC0gYWdlLnFxICsgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz0nIzE5NzZEMicpDQogICAgaWYoaT09NykgcGxvdC5saXN0W1tpXV0gPC0gYWdlLnFxICsgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz0nIzAyODhEMScpDQogICAgaWYoaT09OCkgcGxvdC5saXN0W1tpXV0gPC0gYWdlLnFxICsgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz0nIzAwOTdBNycpDQogICAgaWYoaT09OSkgcGxvdC5saXN0W1tpXV0gPC0gYWdlLnFxICsgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz0nIzAwNzk2QicpDQogICAgaWYoaT09MTApIHBsb3QubGlzdFtbaV1dIDwtIGFnZS5xcSArIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9JyMzODhFM0MnKQ0KICAgIGlmKGk9PTExKSBwbG90Lmxpc3RbW2ldXSA8LSBhZ2UucXEgKyBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPScjNjg5RjM4JykNCiAgICBpZihpPT0xMikgcGxvdC5saXN0W1tpXV0gPC0gYWdlLnFxICsgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz0nI0FGQjQyQicpDQogICAgaWYoaT09MTMpIHBsb3QubGlzdFtbaV1dIDwtIGFnZS5xcSArIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9JyNGQkMwMkQnKQ0KICAgIGlmKGk9PTE0KSBwbG90Lmxpc3RbW2ldXSA8LSBhZ2UucXEgKyBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPScjRkZBMDAwJykNCiAgICANCiAgICAjcGxvdC5saXN0W1tpXV0gPC0gYWdlLnFxICsgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1ldmFsKGFzLmNoYXJhY3Rlcihjb2xvci52ZWN0W2ldKSkpDQogICAgaSA9IGkgKyAxDQp9DQoNCmdyaWQuYXJyYW5nZShwbG90Lmxpc3RbWzFdXSwgDQogICAgICAgICAgICAgcGxvdC5saXN0W1syXV0sDQogICAgICAgICAgICAgcGxvdC5saXN0W1szXV0sDQogICAgICAgICAgICAgcGxvdC5saXN0W1s0XV0sDQogICAgICAgICAgICAgcGxvdC5saXN0W1s1XV0sDQogICAgICAgICAgICAgcGxvdC5saXN0W1s2XV0sDQogICAgICAgICAgICAgcGxvdC5saXN0W1s3XV0sDQogICAgICAgICAgICAgcGxvdC5saXN0W1s4XV0sDQogICAgICAgICAgICAgcGxvdC5saXN0W1s5XV0sDQogICAgICAgICAgICAgcGxvdC5saXN0W1sxMF1dLA0KICAgICAgICAgICAgIHBsb3QubGlzdFtbMTFdXSwNCiAgICAgICAgICAgICBwbG90Lmxpc3RbWzEyXV0sDQogICAgICAgICAgICAgcGxvdC5saXN0W1sxM11dLA0KICAgICAgICAgICAgIHBsb3QubGlzdFtbMTRdXSwgbmNvbD0yKQ0KYGBgDQoNCiMjIyNCb3hwbG90cw0KQWZ0ZXIgY2xlYW5pbmcgdXAgdGhlIGRhdGEgYW5kIGRpc3BsYXlpbmcgaXQgYXMgYSBib3hwbG90IChiZWxvdykgd2UgY2FuIGJldHRlciBhbmFseXplIHRoZSBhZ2UgYW5kIHllYXIgdmFyaWFibGVzLiBXaGlsZSB0aGVyZSBpcyBub3QgYSBzaWduaWZpY2FudCBkaWZmZXJlbmNlIGJldHdlZW4gdGhlIHNlY29uZCBhbmQgdGhpcmQgcXVhcnRpbGVzIGJldHdlZW4gMTk5OSBhbmQgMjAxMiwgaXQgaXMgY2xlYXIgdGhlIG1lZGlhbiBhZ2UgZm9yIHJ1bm5lcnMgaW4gMjAxMiBpcyBsb3dlciB0aGFuIDE5OTkuIEFsc28sIGEgcXVpY2sgbG9vayBhdCB0aGUgYm94cGxvdHMgc2hvd3MgdGhlIG1lZGlhbiBhZ2UgdmFsdWUgZ3JhZHVhbGx5IGRlY3JlYXNpbmcgb3ZlciB0aW1lLCB3aXRoIDIwMTEgYXMgdGhlIG9ubHkgZXhjZXB0aW9uLiBBIGNsb3NlciBsb29rIGF0IHRoZSBib3hwbG90IHN0YXRpc3RpY3Mgc2hvd3MgdGhlIG1lZGlhbiBhZ2Ugb2YgcnVubmVycyBpbiAxOTk5IHdhcyA0MCwgd2hpbGUgdGhlIG1lZGlhbiBhZ2Ugb2YgcnVubmVyIGluIDIwMTIgd2FzIDM2LiBBbm90aGVyIGludGVyZXN0aW5nIG1ldHJpYyBpcyB0aGUgbnVtYmVyIG9mIG9ic2VydmF0aW9ucyBhbHNvIGluY3JlYXNlZCBlYWNoIHllYXIgZnJvbSAzMTg5IGluIDE5OTkgdG8gNzE5MSBpbiAyMDEyLiBUaGUgZGF0YSwgYXMgc2hvd24gaW4gdGhlIGJveHBsb3QsIGRvZXMgbm90IGhhdmUgYW55IHNpZ25pZmljYW50IG91dGxpZXJzIHdoaWNoIGxlYWRzIHRvIHRoZSBjb25jbHVzaW9uIHRoZSBkYXRhIGlzIHJlbGlhYmxlIGFuZCBzaG93cyBhIGdyYWR1YWwgZGVjbGluZSBpbiB0aGUgYWdlIG9mIHJ1bm5lcnMgb3ZlciB0aW1lLg0KYGBge3J9DQoNCiMgc3RyKGNiTWVuU3ViKQ0KIyANCiMgYnAgPC0gYm94cGxvdChjYk1lblN1YiRhZ2UgfiBjYk1lblN1YiR5ZWFyLCB5bGFiID0gIkFnZSIsIHhsYWIgPSAiWWVhciIsIGNvbCA9IGMNCiMgKCJyZWQiLCJzaWVubmEiLCJwYWxldmlvbGV0cmVkMSIsInJveWFsYmx1ZTIiLCJjYWRldGJsdWUiLCJidXJseXdvb2QzIiwiY2hhcnRyZXVzZSIsIA0KIyAiY3lhbjQiLCJkYXJrZ29sZGVucm9kIiwiZGFya29yYW5nZTEiLCJmaXJlYnJpY2siLCJkb2RnZXJibHVlIiwgImZvcmVzdGdyZWVuIiksIGxhcyA9IDIpDQojIGJwDQojIGJwJHN0YXRzWzMsXQ0KDQpicC5wIDwtIGdncGxvdChjYk1lbnNQbG90LCBhZXMoeD15ZWFyLCB5PWFnZSwgZmlsbD15ZWFyKSkgKyBnZW9tX2JveHBsb3QoKSArIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpICsgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcyA9IHByZXR0eShjYk1lbnNQbG90JGFnZSwgbiA9IDEwKSkrDQogICAgc3RhdF9zdW1tYXJ5KGZ1bi55PW1lYW4sIGdlb209InBvaW50Iiwgc2hhcGU9NSwgc2l6ZT00KQ0KYnAucCA8LSBnZ3Bsb3RseShicC5wKQ0KYnAucA0KDQpgYGANCg0KDQojI0Rpc2N1c3Npb24gYW5kIEZ1dHVyZSBXb3Jrcw0KDQojIyBSZWZlcmVuY2VzDQpbMV0gRC4gTGFuZyBhbmQgRC4gTm9sYW4sIERhdGEgU2NpZW5jZSBpbiBSOiBBIENhc2UgU3R1ZGllcyBBcHByb2FjaCB0byBDb21wdXRhdGlvbiBSZWFzb25pbmcgYW5kIFByb2JsZW0gU29sdmluZy4gTmV3IFlvcmssIE5ldyBZb3JrOiBDUkMgUHJlc3MuIA0K